using System;
using Unity.Netcode;
using UnityEngine;
using Random = UnityEngine.Random;

/// <summary>
/// 玩家控制器
/// </summary>
public class PlayerController : NetworkBehaviour
{
    /// <summary>
    /// 移动速度
    /// </summary>
    private float _speed = 3f;

    /// <summary>
    /// 主摄像机
    /// </summary>
    private Camera _mainCamera;

    /// <summary>
    /// 鼠标输入
    /// </summary>
    private Vector3 _mouseInput;

    /// <summary>
    /// 玩家长度组件
    /// </summary>
    private PlayerLength _playerLength;

    /// <summary>
    /// 游戏结束回调
    /// </summary>
    public static Action GameOverAction;
    
    /// <summary>
    /// 复活回调
    /// </summary>
    public static Action ReviveAction;
    
    /// <summary>
    /// 是否死亡
    /// </summary>
    public NetworkVariable<bool> IsDeath = new NetworkVariable<bool>(false);
    
    /// <summary>
    /// 当前网络对象创建时回调
    /// </summary>
    public override void OnNetworkSpawn()
    {
        _mainCamera = Camera.main;
        _playerLength = GetComponent<PlayerLength>();

        if (IsServer)
        {
            // 随机位置
            transform.position = new Vector3(Random.Range(-5f, 3f), Random.Range(-5f, 3f),0f);   
        }
    }

    // Update is called once per frame
    void Update()
    {
        // 不是拥有者退出
        if(!IsOwner)
            return;

        // 移动玩家
        MovePlayer(Time.deltaTime);

        // 复活
        Revive();
    }

    /// <summary>
    /// 移动玩家
    /// </summary>
    private void MovePlayer(float updateTime)
    {
        if(IsDeath.Value)
            return;
        
        if (Input.GetMouseButton(0))
        {
            // ------ 移动 ------
            // 鼠标位置
            _mouseInput = Input.mousePosition;
            // 获得鼠标的世界坐标
            Vector3 mouseWorldCoordinates = _mainCamera.ScreenToWorldPoint(_mouseInput);
            mouseWorldCoordinates.z = 0;
           // 移动玩家
           MovePlayerServerRpc(mouseWorldCoordinates,updateTime);
        }
    }

    /// <summary>
    /// 复活
    /// </summary>
    private void Revive()
    {
        if (IsDeath.Value && Input.GetMouseButton(1))
        {
            // 通知服务器复活
            ReviveServerRpc();
            // 复活回调
            ReviveAction?.Invoke();
        }
    }

    /// <summary>
    /// 服务器 - 移动玩家
    /// </summary>
    /// <param name="mouseWorldCoordinates"></param>
    /// <param name="updateTime"></param>
    [ServerRpc]
    private void MovePlayerServerRpc(Vector3 mouseWorldCoordinates, float updateTime)
    {
        // 移动
        transform.position =
            Vector3.MoveTowards(transform.position, mouseWorldCoordinates, updateTime * _speed);
            
        // ------ 旋转 ------
        if (mouseWorldCoordinates != transform.position)
        {
            // 移动方向
            var moveDir = mouseWorldCoordinates - transform.position;
                
            // 清空z轴方向的值
            moveDir.z = 0;
                
            // 设置朝向
            transform.up = moveDir; 
        }
    }
    
    /// <summary>
    /// 复活
    /// </summary>
    [Rpc(SendTo.Server)]
    private void ReviveServerRpc()
    {
        IsDeath.Value = false;
        transform.localScale = Vector3.one;
        transform.localPosition = new Vector3(Random.Range(-5f, 3f), Random.Range(-5f, 3f),0f);
    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        // 不是玩家退出
        if(!other.gameObject.CompareTag("Player"))return;
        // 不是服务器退出
        if(!IsServer)return;
        
        // 头碰头 - 判断谁是胜利者
        if (other.gameObject.TryGetComponent(out PlayerLength playerLength))
        {
            // log
            Debug.Log("头碰头");
            
            var playerSelf = new PlayerData()
            {
                PlayerId = OwnerClientId,
                Lenght = _playerLength.length.Value,
            };
            var playerOther = new PlayerData()
            {
                PlayerId = playerLength.OwnerClientId,
                Lenght = playerLength.length.Value,
            };
            
            // 判断谁是胜利者
            DetermineWinner(playerSelf, playerOther);
        }
        // 头碰尾 - 直接失败
        else if (other.gameObject.TryGetComponent(out PlayerTail playerTail))
        {
            // log
            Debug.Log("头碰尾");
            
            // 对手
            var otherId = playerTail.networkedOwner.GetComponent<PlayerLength>().OwnerClientId;
            // 通知服务器
            WinInformationServerRpc(otherId,OwnerClientId);
            
            // 死亡
            IsDeath.Value = true;
            // 隐藏
            transform.localScale = Vector3.zero;
            // 删除长度
            _playerLength.length.Value = 1;
            // 删除尾巴
            _playerLength.DestroyTail();
        }
    }
    
    #region 方法
    
    /// <summary>
    /// 判断谁是胜利者
    /// </summary>
    /// <param name="playerSelf">自己</param>
    /// <param name="playerOther">玩家02</param>
    private void DetermineWinner(PlayerData playerSelf, PlayerData playerOther)
    {
        // 自己胜利
        if (playerSelf.Lenght > playerOther.Lenght)
            WinInformationServerRpc(playerSelf.PlayerId, playerOther.PlayerId);
        // 自己胜利失败
        else
        {
            WinInformationServerRpc(playerOther.PlayerId, playerSelf.PlayerId);
            
            // 死亡
            IsDeath.Value = true;
            // 隐藏
            transform.localScale = Vector3.zero;
            // 删除长度
            _playerLength.length.Value = 1;
            // 删除尾巴
            _playerLength.DestroyTail();
        }
    }

    /// <summary>
    /// 胜利信息
    /// </summary>
    /// <param name="winner"></param>
    /// <param name="loser"></param>
    [Rpc(SendTo.Server)]
    private void WinInformationServerRpc(ulong winner, ulong loser)
    {
        // 发给胜利客户端的参数
        RpcParams clientRpcParamsWinner = new RpcParams()
        {
            // 发送参数
            Send = new RpcSendParams()
            {
                // 目标客户
                Target = RpcTarget.Single(winner,RpcTargetUse.Temp)
            }
        };
        // 吃掉一个玩家
        EatPlayerClientRpc(clientRpcParamsWinner);

        // 发给失败客户端的参数
        RpcParams clientRpcParamsLoser = new RpcParams()
        {
            // 发送参数
            Send = new RpcSendParams()
            {
                // 目标客户
                Target = RpcTarget.Single(loser,RpcTargetUse.Temp)
            }
        };
        // 游戏结束
        GameOverClientRpc(clientRpcParamsLoser);
    }

    /// <summary>
    /// 吃掉了玩家
    /// </summary>
    /// <param name="clientRpcParams"></param>
    [Rpc(SendTo.SpecifiedInParams)]
    private void EatPlayerClientRpc(RpcParams clientRpcParams = default)
    {
        if(!IsOwner)return;
        // log
        Debug.Log("吃掉了一个玩家");
    }

    /// <summary>
    /// 游戏结束
    /// </summary>
    [Rpc(SendTo.SpecifiedInParams)]
    private void GameOverClientRpc(RpcParams clientRpcParams = default)
    {
        if(!IsOwner)return;
        // log
        Debug.Log("游戏结束");
        // 回调
        GameOverAction?.Invoke();
    }
    #endregion
    
    /// <summary>
    /// 玩家数据-继承与网络序列化类用于网络传输
    /// </summary>
    struct PlayerData : INetworkSerializable
    {
        // 玩家id
        public ulong PlayerId;
        // 长度
        public ushort Lenght;
        /// <summary>
        /// 序列换方法
        /// </summary>
        /// <param name="serializer"></param>
        /// <typeparam name="T"></typeparam>
        public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
        {
            serializer.SerializeValue(ref PlayerId);
            serializer.SerializeValue(ref Lenght);
        }
    }
}
